﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml.Linq;
using MyGame.Objects;

namespace MyGame
{
	public partial class MainPage : UserControl
	{
		//TODO - Osetrit level ktery neni definovany
		private int actualLevelNumber = 1; //actual level number
		//private Level actualLevel = new Level(); //mozna Zamenit za myLevel

		private Bandit myBandit = new Bandit();
		Image myBanditImage = new Image() { Source = new BitmapImage(new Uri("Images/Bandit.png", UriKind.Relative)), Width = Settings.CellSizeInPixel };
		
		private Level actualLevel = new Level();

		//List<Level> listOfLevels = new List<Level>();   //list of levels - loading levels at start

		DateTime _lastTime; //*********************************************************************************

		private DateTime _LastExecution = DateTime.MinValue;

		public MainPage()
		{
			// Required to initialize variables
			actualLevel = LoadActualLevel();
			//listOfLevels = LoadActualLevel();
			InitializeComponent();
			newGame();

			//*******************************************************************************************************
			_lastTime = DateTime.Now;
			timer = new DispatcherTimer();
			timer.Interval = TimeSpan.FromMilliseconds(300);
			timer.Tick += new EventHandler(timer_Tick);
			timer.Start();
		}

		//*******************************************************************************************************
		DispatcherTimer timer;
		void timer_Tick(object sender, EventArgs e)
		{
			OnTimerGabbo();
		}

		private void OnTimerGabbo()
		{
			
		}

		/*private void OnTimer()
		{
			try
			{
				DateTime now = DateTime.Now;
				if (game.State != GameState.Playing) // if we're not playing, nothing to update
				{
					_lastTime = now;
					return;
				}

				// we're playing, calculate how much time passed since the last update
				double elapsedMsec = (now - _lastTime).TotalMilliseconds;
				if (elapsedMsec < 1) // if the timer was called too quickly
				{
					return; // wait for next timer
				}
				_lastTime = now;

				// store the fraction of the elapsedMsec - we have to add it in the high resolution timer
				double firstAddNumber = elapsedMsec - Math.Floor(elapsedMsec);
				int elapsedMsecInt = (int)elapsedMsec;

				// update bonuses position
				for (int i = game.Bonuses.Count - 1; i >= 0; i--)
				{
					Bonus bonus = game.Bonuses[i];
					bool isGameRestarted = false;

					bool isAdded = false;
					for (int j = 0; j < elapsedMsecInt; j++)
					{
						if (!isAdded)
						{
							bonus.UpdatePos(1 + firstAddNumber);
							isAdded = true;
						}
						else
						{
							bonus.UpdatePos(1);
						}

						HitTestResult hit;
						hit = bonus.HitTestPaddle(game.Paddle);
						if (hit == HitTestResult.Paddle) // if we hit the paddle
						{
							game.Bonuses.Remove(bonus);
							bonus.RemoveFromScreen();
							game.ReceiveBonus(bonus.Contents, out isGameRestarted);
							break;
						}

						hit = bonus.HitTestScreenBottom();
						if (hit == HitTestResult.OutOfScreenBottom)
						{
							game.Bonuses.Remove(bonus);
							bonus.RemoveFromScreen();
							break;
						}
					} // for (int j = 0; j < elapsedMsecInt; j++)
					if (isGameRestarted) break; // if game was restarted no need to get other bonuses
				} // for (int i = game.Bonuses.Count - 1; i >= 0; i--)

				// update balls position
				for (int i = game.Balls.Count - 1; i >= 0; i--)
				{
					Ball ball = game.Balls[i];
					bool isGameRestarted = false;

					bool isAdded = false;
					for (int j = 0; j < elapsedMsecInt; j++)
					{
						if (!isAdded)
						{
							ball.UpdatePos(game.Paddle, 1 + firstAddNumber);
							isAdded = true;
						}
						else
						{
							ball.UpdatePos(game.Paddle, 1);
						}

						// calc ball reflection off:
						// 1. bricks
						// 2. paddle
						// 3. walls
						HitTestResult hit;

						hit = ball.HitTestBricks(game, out isGameRestarted);
						if (isGameRestarted) break;
						if (ball.IsRemoved) break; // if the ball was removed we no longer need to update it

						hit = ball.HitTestPaddle(game.Paddle);
						if (ball.IsRemoved) break; // if the ball was removed we no longer need to update it

						hit = ball.HitTestWalls();
						if (hit == HitTestResult.BottomRail)
						{
							if (game.Balls.Count == 1) // if last ball
							{
								game.RemoveLife();
							}
							else
							{
								game.Balls.Remove(ball);
								ball.RemoveFromScreen();
							}
						}
					} // for (int j = 0; j < elapsedMsecInt; j++)

					if (isGameRestarted) break; // if game was restarted no need to update other balls
				} // for (int i = game.Balls.Count - 1; i >= 0; i--)
			}
			catch (Exception e)
			{
				Globals.ReportError(e);
			}
			/*            game.DebugStr = String.Format("ball: {0}, {1}; brick: {2}, {3}",
							(int)game.Balls[0].PosScreen.X, (int)game.Balls[0].PosScreen.Y,
							(int)game.Level.Bricks[0].Pos.X * Globals.Zoom, (int)game.Level.Bricks[0].Pos.Y * Globals.Zoom);*/
		/*
		}*/





















		private void newGame()
		{

			//IniciateFirstLevel();
			//myLevel = listOfLevels.Where(x => x.LevelNumber == actualLevelNumber).FirstOrDefault();
			DrawLevel();

			//Load level
			//FIRST
			myBandit.PositionX = actualLevel.StartingX;
			myBandit.PositionY = actualLevel.StartingY;
	
			//Set bandit starting position

			myBanditImage.SetValue(Canvas.TopProperty, GridToPixelConverter.GetPixelFromGrid(myBandit.PositionY));
			myBanditImage.SetValue(Canvas.LeftProperty, GridToPixelConverter.GetPixelFromGrid(myBandit.PositionX));
			GameField.Children.Add(myBanditImage);
		}

		private void UserControl_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
		{
			if ((DateTime.Now - _LastExecution).TotalMilliseconds > 900)
			{
				if (e.Key.Equals(Key.Up))
				{
					myBandit.moveUp();
					if (!myBandit.CheckForCollision(actualLevel))
					{
						myBandit.updatePosition();
					}
					ImageUpdatePosition(myBanditImage, myBandit.PositionX, myBandit.PositionY);
				}
				if (e.Key.Equals(Key.Down))
				{
					myBandit.moveDown();
					if (!myBandit.CheckForCollision(actualLevel))
					{
						myBandit.updatePosition();
					}
					ImageUpdatePosition(myBanditImage, myBandit.PositionX, myBandit.PositionY);
				}
				if (e.Key.Equals(Key.Left))
				{
					myBandit.moveLeft();
					if (!myBandit.CheckForCollision(actualLevel))
					{
						myBandit.updatePosition();
					}
					ImageUpdatePosition(myBanditImage, myBandit.PositionX, myBandit.PositionY);
				}
				if (e.Key.Equals(Key.Right))
				{
					myBandit.moveRight();
					if (!myBandit.CheckForCollision(actualLevel))
					{
						myBandit.updatePosition();
					}
					ImageUpdatePosition(myBanditImage, myBandit.PositionX, myBandit.PositionY);
				}
				_LastExecution = DateTime.Now;
			}
		}

		//Updates position of image objects
		private void ImageUpdatePosition(Image image, int X, int Y)
		{
			image.SetValue(Canvas.TopProperty, GridToPixelConverter.GetPixelFromGrid(Y));
			image.SetValue(Canvas.LeftProperty, GridToPixelConverter.GetPixelFromGrid(X));
		}

		private void DrawLevel()
		{
			//'#' Wall 
			//' ' Empty floor cell
			//'?' Question
			//'@' Finnish
			//'$' 
			//'.' 
			//'!' 

			foreach (var cell in actualLevel.cellList)
			{
				switch (cell.CellType)
				{
					//    //TESTING FIELDS
					//case 'A':
					//    Image A = new Image() { Source = new BitmapImage(new Uri("Images/A.png", UriKind.Relative)), Width = Settings.CellSizeInPixel };
					//    A.SetValue(Canvas.TopProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionY));
					//    A.SetValue(Canvas.LeftProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionX));
					//    GameField.Children.Add(A);
					//    break;
					//case 'B':
					//    Image B = new Image() { Source = new BitmapImage(new Uri("Images/B.png", UriKind.Relative)), Width = Settings.CellSizeInPixel };
					//    B.SetValue(Canvas.TopProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionY));
					//    B.SetValue(Canvas.LeftProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionX));
					//    GameField.Children.Add(B);
					//    break;
					//case 'C':
					//    Image C = new Image() { Source = new BitmapImage(new Uri("Images/C.png", UriKind.Relative)), Width = Settings.CellSizeInPixel };
					//    C.SetValue(Canvas.TopProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionY));
					//    C.SetValue(Canvas.LeftProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionX));
					//    GameField.Children.Add(C);
					//    break;
					//case 'D':
					//    Image D = new Image() { Source = new BitmapImage(new Uri("Images/D.png", UriKind.Relative)), Width = Settings.CellSizeInPixel };
					//    D.SetValue(Canvas.TopProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionY));
					//    D.SetValue(Canvas.LeftProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionX));
					//    GameField.Children.Add(D);
					//    break;

						//CELLS
					case '#':   // Walls
						Image WallPic = new Image() { Source = new BitmapImage(new Uri("Images/Wall.png", UriKind.Relative)), Width = Settings.CellSizeInPixel };
						WallPic.SetValue(Canvas.TopProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionY));
						WallPic.SetValue(Canvas.LeftProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionX));
						GameField.Children.Add(WallPic);
						break;
					case ' ':   // Empty cell
						Image EmptyPic = new Image() { Source = new BitmapImage(new Uri("Images/Cell.png", UriKind.Relative)), Width = Settings.CellSizeInPixel };
						EmptyPic.SetValue(Canvas.TopProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionY));
						EmptyPic.SetValue(Canvas.LeftProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionX));
						GameField.Children.Add(EmptyPic);
						break;
					case '?':   // Question
						Image EmptyPic2 = new Image() { Source = new BitmapImage(new Uri("Images/Cell.png", UriKind.Relative)), Width = Settings.CellSizeInPixel };
						EmptyPic2.SetValue(Canvas.TopProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionY));
						EmptyPic2.SetValue(Canvas.LeftProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionX));
						GameField.Children.Add(EmptyPic2);
						Image QuestionPic = new Image() { Source = new BitmapImage(new Uri("Images/Question.png", UriKind.Relative)), Width = Settings.CellSizeInPixel };
						QuestionPic.SetValue(Canvas.TopProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionY));
						QuestionPic.SetValue(Canvas.LeftProperty, GridToPixelConverter.GetPixelFromGrid(cell.PositionX));
						GameField.Children.Add(QuestionPic);
						break;
				}
				
			}
			
		}


		//TODO - Osetreni Chyb pri neexistujicim attributu nebo hodnote ktera neni Int.
		//private List<Level> LoadLevelList()
		//{
		//    XDocument xdoc = XDocument.Load("Levels/levels.xml");
		//    if (xdoc != null)
		//    {
		//        var levels =
		//            (from l in xdoc.Descendants("Level")
		//             select new Level()
		//             {
		//                 LevelNumber = Convert.ToInt32(l.Attribute("levelNumber").Value),
		//                 StartingX = Convert.ToInt32(l.Attribute("startingX").Value),
		//                 StartingY = Convert.ToInt32(l.Attribute("startingY").Value),
		//                 cellList = (from c in l.Descendants("Cell")
		//                             select new Cell
		//                             {
		//                                 CellType = Convert.ToChar(c.Attribute("CellType").Value),
		//                                 PositionX = Convert.ToInt32(c.Attribute("PositionX").Value),
		//                                 PositionY = Convert.ToInt32(c.Attribute("PositionY").Value)
		//                             }).ToList()
		//             }
		//            ).ToList();
		//        return levels;
		//    }
		//    List<Level> empty = new List<Level>();
		//    return empty;
		//}

		//loading just actual level
		//TODO - change structure of level variable (not list)
		private Level LoadActualLevel()
		{
			XDocument xdoc = XDocument.Load(string.Format("Levels/{0}.xml", actualLevelNumber.ToString("0000")));
			if (xdoc != null)
			{
				var xmlLevel =
					(from l in xdoc.Descendants("Level")
					 //where (int)l.Attribute("LevelNumber") == actualLevelNumber
					 select new Level()
					 {
						 LevelNumber = Convert.ToInt32(l.Attribute("levelNumber").Value),
						 StartingX = Convert.ToInt32(l.Attribute("startingX").Value),
						 StartingY = Convert.ToInt32(l.Attribute("startingY").Value),
						 cellList = (from c in l.Descendants("Cell")
									 select new Cell
									 {
										 CellType = Convert.ToChar(c.Attribute("CellType").Value),
										 PositionX = Convert.ToInt32(c.Attribute("PositionX").Value),
										 PositionY = Convert.ToInt32(c.Attribute("PositionY").Value)
									 }).ToList()
					 }
					 ).FirstOrDefault();
					//).ToList();
				return xmlLevel;
			}
			Level empty = new Level();
			return empty;
		}

	}
}